﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SynoManager.GUI;
using System.IO;

namespace SynoManager.DownloadStation
{
    [ServiceDependency(typeof(DownloadStationService))]
    public class DownloadGuiPlugin : IGuiPlugin
    {
        private IHost host;
        private DownloadGuiTab tab;
        internal DownloadStationService service;

        #region Plugin

        private bool tabActive;
        public bool TabActive
        {
            set
            {
                tabActive = value;
                updateToolStrip();
            }
            get
            {
                return tabActive;
            }
        }

        /// <summary>
        /// Gets the priority the tabcontrol order
        /// </summary>
        public int TabPriority
        {
            get { return 100; }
        }

        /// <summary>
        /// Initializes the plugin, enabling it to hook on the events of the device or it's services.
        /// </summary>
        /// <param name="device">The device for which the initialize.</param>
        /// <remarks>It will called upon every new connection of a device, so it is possible it will be called multiple times per lifetime of a plugin.</remarks>
        public void Initialize(SynoDevice device)
        {
            service = device.FindService<DownloadStationService>();
            Debug.Assert(service != null, "DownloadStationService could not be found");
            service.Plugin = this;
        }

        /// <summary>
        /// Function that is called when the connection state has changed
        /// </summary>
        /// <param name="isConnected">Returns true if the device is connected.</param>
        /// <param name="wasConnected">Returns true if the device has successfully connected in the past</param>
        /// <remarks>This function is called in a thread-safe way, so no Invoke is required.</remarks>
        public void OnConnectionStateChange(bool isConnected, bool wasConnected)
        {
            toolStrip.Enabled = menuStrip.Enabled = isConnected;
            Tab.Enabled = isConnected;
        }

        /// <summary>
        /// Function that is called by the Preference Form to populate the treeview
        /// </summary>
        /// <param name="treeView">Treeview where the plugin can add it's node(s). <see cref="TreeNode.Tag"/> should contain PreferencePanel.</param>
        public void PopulatePreferencesForm(TreeViewEx treeView)
        {
            var preferencesForm = new DownloadStationPreferencesPanel(this.service);
            var node = treeView.Nodes.Add("Download Station", null, preferencesForm);
            node.Nodes.Add("Queue", null, new QueuePreferencesPanel(this.service));
            node.Nodes.Add("Files", null, new FilesPreferencesPanel(this.service));
            var pluginNode = node.Nodes.Add("Plugins", null, new PluginsPreferencesPanel(this.service));
            foreach (var plugin in service.Plugins.AllPlugins)
            {
                if (plugin is IDownloadStationPreferencePanelPlugin)
                {
                    var p = (IDownloadStationPreferencePanelPlugin) plugin;
                    pluginNode.Nodes.Add(p.PreferenceNodeText, p.PreferenceNodeImage, p.PreferencePanel);
                }
            }
            node.Nodes.Add("Advanced", null, new AdvancedPreferencesPanel(this.service));
            node.Expand();
        }

        private ToolStripDropDownButton stripAdd;
        private ToolStripButton stripProperties;
        private ToolStripButton stripPause;
        private ToolStripButton stripResume;
        private ToolStripItem currentDownStatus;
        private ToolStripItem currentUpStatus;

        public Control MainControl
        {
            get
            {
                return Tab;
            }
        }

        public DownloadGuiTab Tab
        {
            get
            {
                if (tab == null)
                {
                    tab = new DownloadGuiTab(this);
                    updateToolStrip();
                }
                return tab;
            }
        }

        internal IHost Host
        {
            get { return host; }
        }

        internal void updateToolStrip()
        {
            stripProperties.Enabled = (tabActive) && (tab != null) && tab.AllowProperties;
            stripPause.Enabled = (tabActive) && (tab != null) && tab.AllowPause;
            stripResume.Enabled = (tabActive) && (tab != null) && tab.AllowResume;
        }

        internal void updateTotals()
        {
            if (currentUpStatus.Owner.InvokeRequired)
            {
                currentUpStatus.Owner.Invoke(new MethodInvoker(updateTotals));
                return;
            }
            currentDownStatus.Text = service.TotalRateDown.ToByteString() + "/s";
            currentUpStatus.Text = service.TotalRateUp.ToByteString() + "/s";
        }

        internal ToolStripDropDownItem menuStrip;
        internal ToolStrip toolStrip;

        public void InitializeHost(IHost host)
        {
            this.host = host;

            // Menu
            menuStrip = (ToolStripDropDownItem)host.Menu.Items.Add("&Downloads");
            
            var addTaskMenu = new ToolStripMenuItem("Add Task", Properties.Resources.package_add);

            addTaskMenu.DropDownItems.Add(new ToolStripMenuItem("File...", Properties.Resources.package_add, addFileTask, Keys.Control | Keys.O));
            addTaskMenu.DropDownItems.Add(new ToolStripMenuItem("Url...", Properties.Resources.package_add, addUrlTask, Keys.Control | Keys.U));
            menuStrip.DropDownItems.Add(addTaskMenu);
            
            menuStrip.DropDownItems.Add(new ToolStripSeparator());
            menuStrip.DropDownItems.Add("Pause All", Properties.Resources.control_pause, pauseAllTasks);
            menuStrip.DropDownItems.Add("Resume All", Properties.Resources.control_play, resumeAllTasks);

            menuStrip.DropDownItems.Add(new ToolStripSeparator());
            menuStrip.DropDownItems.Add("Clear Completed", Properties.Resources.bin, cleanCompleted);

            // Toolstrip
            toolStrip = new ToolStrip();
            toolStrip.Location = new Point(3, 24);
            
            stripAdd = new ToolStripDropDownButton("Add Task", Properties.Resources.package_add);
            stripAdd.DropDownItems.Add("File...", Properties.Resources.package_add, addFileTask);
            stripAdd.DropDownItems.Add("Url...", Properties.Resources.package_add, addUrlTask);
            toolStrip.Items.Add(stripAdd);

            toolStrip.Items.Add(new ToolStripSeparator());
            stripPause = toolStrip.Items.AddButton("Pause", Properties.Resources.control_pause_blue, pauseSelectedTask);
            stripResume = toolStrip.Items.AddButton("Resume", Properties.Resources.control_play_blue, resumeSelectedTask);
            toolStrip.Items.Add(new ToolStripSeparator());
            toolStrip.Items.AddButton("Pause All", Properties.Resources.control_pause, pauseAllTasks);
            toolStrip.Items.AddButton("Resume All", Properties.Resources.control_play, resumeAllTasks);
            toolStrip.Items.Add(new ToolStripSeparator());
            stripProperties = toolStrip.Items.AddButton("Properties", Properties.Resources.information, taskProperties);
            toolStrip.Items.Add(new ToolStripSeparator());
            toolStrip.Items.AddButton("Clear Completed", Properties.Resources.bin, cleanCompleted);
            toolStrip.Items.Add(new ToolStripSeparator());
            toolStrip.Items.AddButton("Open Download Folder", Properties.Resources.folder_go, openDownloadFolder);

            host.ToolStrips.TopToolStripPanel.Controls.Add(toolStrip);

            // Status Strip
            currentDownStatus = host.StatusStrip.Items.Add("? B/s", Properties.Resources.arrow_down);
            currentUpStatus = host.StatusStrip.Items.Add("? B/s", Properties.Resources.arrow_up);

            // Notify Icon
            host.NotifyIcon.ContextMenuStrip.Items.Insert(1, new ToolStripMenuItem("Add...", Properties.Resources.package_add, addUrlTask));
            host.NotifyIcon.ContextMenuStrip.Items.Insert(1, new ToolStripSeparator());

            if (HostInitialized != null)
                HostInitialized(this, EventArgs.Empty);
        }

        public event EventHandler HostInitialized;

        private void openDownloadFolder(object sender, EventArgs e)
        {
            if (Directory.Exists(service.DownloadFolder))
            {
                Process.Start(service.DownloadFolder);
            }
            else
            {
                MessageBox.Show("Could not open download folder.\nPlease make sure the folder is accessible",
                                "Open Download folder", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region Functions
        private void addFileTask(object sender, EventArgs e)
        {
            OpenDownloadFileDialog dialog = new OpenDownloadFileDialog(service);
            dialog.Execute(tab.ParentForm);
        }

        private void addUrlTask(object sender, EventArgs e)
        {
            AddDownloadTaskDialog dialog = new AddDownloadTaskDialog();
            if (dialog.ShowDialog(tab.ParentForm) == DialogResult.OK)
            {
                bool showProgress = false;
                showProgress = (dialog.Locations.Count() > 2);
                ProgressBarInfo progress = null;

                if (showProgress)
                {
                    progress = new ProgressBarInfo();
                    ((Form)this.Host).AddOwnedForm(progress);
                    //progress.TopMost = true;
                    progress.Show();

                    progress.progressBar1.Maximum = dialog.Locations.Count() + 1;
                    progress.progressBar1.Minimum = 0;

                }
                int curr = 0;
                foreach (var location in dialog.Locations)
                {
                    Application.DoEvents();
                    curr++;
                    if (showProgress)
                    {
                        Application.DoEvents();
                        progress.progressBar1.Value = curr;
                        progress.Text = string.Format("Adding URLs : {0} of {1}", curr.ToString(), dialog.Locations.Count().ToString());
                        progress.Refresh();
                    }
                    Application.DoEvents();
                    service.AddUrl(location);
                    Application.DoEvents();

                }

                if (showProgress)
                {
                    progress.Close();
                    progress.Dispose();
                }
            }
        }

        private void taskProperties(object sender, EventArgs e)
        {
            tab.ShowProperties();
        }

        private void resumeAllTasks(object sender, EventArgs e)
        {
            service.ResumeAll();
        }

        private void pauseAllTasks(object sender, EventArgs e)
        {
            service.PauseAll();
        }

        private void resumeSelectedTask(object sender, EventArgs e)
        {
            tab.ResumeSelected();
        }

        private void pauseSelectedTask(object sender, EventArgs e)
        {
            tab.PauseSelected();
        }

        private void cleanCompleted(object sender, EventArgs e)
        {
            service.ClearCompleted();
        }
        #endregion
    }
}
